part of 'temp.dart';

extension ObjectConvert on Object {
  String get toStr => toString();
  int get toInt => int.parse(toStr);
  double get toDouble => double.parse(toStr);
  DateTime get toDate => DateTime.fromMicrosecondsSinceEpoch(toInt);
  bool get toBool => toInt!=0;
}

extension DateTimeConvert on DateTime {
  int get toInt => microsecondsSinceEpoch;
}

class TempSensorData {
  final String id;
  String name;
  String adj;
  double temp;
  bool alarm;
  DateTime age;
  int energy;
  bool get online => DateTime.now().difference(age).inSeconds<30;
  String get label => (name == "") ? id : name;

  TempSensorData(this.id, this.name, this.adj, this.temp, this.alarm,  this.age, this.energy);
  TempSensorData.map(Map<String, Object?>m) : this(m['id']!.toStr, m['name']!.toStr, m['adj']!.toStr, m['temp']!.toDouble, m['alarm']!.toBool, m['age']!.toDate, m['energy']!.toInt);

  Map<String, Object> toMap() {
    return {
      'id': id,
      'name': name,
      'adj': adj,
      'temp': temp,
      'alarm': alarm?1:0,
      'age': age.toInt,
      'energy': energy,
    };
  }
  
  bool update(TempSensorData data) {
    bool ok = false;
    if (temp != data.temp) { temp = data.temp; ok = true; }
    if (alarm != data.alarm) { alarm = data.alarm; ok = true; }
    if (age != data.age) { age = data.age; ok = true; }
    if (energy != data.energy) { energy = data.energy; ok = true; }
    return ok;
  }
}

class TempSensor {
  late TempSensorData data;
  late bool hide;
  TempSensor(this.data, {this.hide=false});
  TempSensor.map(Map<String, Object?>m) : this(TempSensorData.map(m), hide: m['hide']!.toBool);
  TempSensor.full(String id, double temp, bool alarm, this.hide, int energy) {
    data = TempSensorData(id, id, "", temp, alarm, DateTime(2023), energy);
  }
  TempSensor.empty() : this.full("null", 0, false, true, 0);
  Map<String, Object?> toMap() {
    var m = data.toMap();
    m['hide'] = hide?1:0;
    return m;
  }
}

//String u82hex(int d) => d.toRadixString(16);
String u82hex(ByteData d, int off) => d.getUint8(off).toRadixString(16);
ByteData convertIntListToByteData(List<int> intList) {
  final buffer = Uint8List.fromList(intList).buffer;
  return ByteData.view(buffer);
}
class TempSensorCodec implements MessageCodec<TempSensorData> {
  const TempSensorCodec();

  @override
  TempSensorData? decodeMessage(ByteData? message) {
    if (message == null)  {
      return TempSensorData("null", "", "", 0.1, true, DateTime.now(), 0);
    }
    if (message.lengthInBytes != 7) {
      return TempSensorData("ill", "", "", message.lengthInBytes.toDouble(), true, DateTime.now(), 0);
    }
    String id = "${u82hex(message,0)}-${u82hex(message,1)}-${u82hex(message,2)}-${u82hex(message,3)}";
    int ad = message.getUint16(4, Endian.little);
    int energy = message.getUint8(6);
    bool alarm = (ad & 2)!=0;
    ad = ad >> 2;
    return TempSensorData(id, "", "", getTemp(ad.toDouble()), alarm, DateTime.now(), energy);
  }

  @override
  ByteData? encodeMessage(TempSensorData? message) => null;
}

class Utf8StringCodec implements MessageCodec<String> {
  const Utf8StringCodec();

  @override
  String? decodeMessage(ByteData? message) {
    if (message == null)  return null;
    return utf8.decode(message.buffer.asUint8List());
  }

  @override
  ByteData? encodeMessage(String? message) {
    if (message == null)  return null;
    return convertIntListToByteData(utf8.encode(message));
  }
}
